package org.lboot.flow.processor.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.lboot.flow.constant.FlowNodeTypeConst;
import org.lboot.flow.constant.FlowWorkStatusEnum;
import org.lboot.flow.event.FlowEventConsumer;
import org.lboot.flow.event.system.FlowProcessEvent;
import org.lboot.flow.loader.EventProcessLoader;
import org.lboot.flow.loader.TaskUserLoader;
import org.lboot.flow.model.FlowModel;
import org.lboot.flow.model.node.BaseModel;
import org.lboot.flow.model.node.EventModel;
import org.lboot.flow.module.assign.FlowTaskAssignService;
import org.lboot.flow.module.audit.FlowAuditService;
import org.lboot.flow.module.event.FlowCustomEvent;
import org.lboot.flow.module.event.FlowCustomEventService;
import org.lboot.flow.module.work.FlowWork;
import org.lboot.flow.module.work.FlowWorkService;
import org.lboot.flow.module.work.params.FlowTaskParams;
import org.lboot.flow.parser.FlowNodeParser;
import org.lboot.flow.processor.FlowNodeProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

@Slf4j
@Service
@AllArgsConstructor
public class EventNodeProcessorImpl implements FlowNodeProcessor {
    FlowNodeParser flowNodeParser;

    FlowWorkService flowWorkService;

    FlowAuditService flowAuditService;

    FlowTaskAssignService flowTaskAssignService;

    TaskUserLoader taskUserLoader;

    List<EventProcessLoader> eventProcessLoaders;

    FlowCustomEventService eventService;

    List<FlowEventConsumer> consumers;

    @Resource
    ApplicationContext context;
    @Override
    public String getNodeType() {
        return FlowNodeTypeConst.EVENT_NODE;
    }

    @Override
    @SneakyThrows
    public void process(FlowWork flowWork, FlowTaskParams taskParams) {
        FlowWork oldFlow = new FlowWork();
        BeanUtil.copyProperties(flowWork,oldFlow, CopyOptions.create().setIgnoreError(true).setIgnoreNullValue(true));
        // 流程执行到下一步
        BaseModel currentNode = flowWork.getNodeModel(flowWork.getCurrentNodeId());
        EventModel eventModel = (EventModel) currentNode;
        // 获取事件ID
        String eventId = eventModel.getEventId();
        // 获取自定义事件列表
        List<FlowCustomEvent> events = eventService.getByEventId(eventId);
        // 如果为空 阻塞
        if (events.isEmpty()){
            log.warn("流程实例:[{}]节点:[{}]对应的事件:[{}]不存在", flowWork.getId(), flowWork.getCurrentNodeId(), eventId);
            // 流程进入阻塞状态
            flowWork.setFlowWorkStatus(FlowWorkStatusEnum.BLOCKED.value);
            flowWorkService.updateOne(flowWork);
        }
        // 不为空获取第一个事件 投递
        FlowCustomEvent event = events.get(0);
        // 异步事件直接触发之后进入下一个状态
        if (event.getIsAsync()){
            for (FlowEventConsumer consumer:consumers){
                if (event.getEventId().equals(consumer.eventId())){
                    consumer.consume(event);
                }
            }
        }
        for (EventProcessLoader eventProcessLoader:eventProcessLoaders){
            if (eventId.equals(eventProcessLoader.eventId())){
                eventProcessLoader.process();
            }
        }
        // 流转到下一个节点
        String nextNodeId = currentNode.getNextNodeId();
        BaseModel nextNode = flowWork.getNodeModel(flowWork.getNextNodeId());
        flowWork.setCurrentNodeId(nextNodeId);
        flowWork.setCurrentNodeType(nextNode.getNodeType());
        flowWork.setNextNodeId(nextNode.getNextNodeId());
        flowWorkService.updateOne(flowWork);
        // 发布流程节点流程流转事件
        context.publishEvent(new FlowProcessEvent(this,oldFlow,flowWork,taskParams));
    }

    @Override
    public void back(FlowWork flowWork, FlowTaskParams taskParams) {

    }
}
